require 'active_support/core_ext/module/aliasing'
require "active_support/concern"
require "redcarpet"

module Dionysus
  module Redcarpet
    extend ActiveSupport::Concern

    # The Syntax for a file directive (first line of the file):
    # 
    # @example Hash Comment
    #   # -*- md:DIRECTIVE -*-
    #
    # @example Double Slash Comment
    #   // -*- md:DIRECTIVE -*-
    FILE_DIRECTIVE_REGEXP = /\A(?:#|\/\/)\s*-\*-\s*(md):\s*(\S+)\s*-\*-\s*\n/

    # The Syntax for an inline directive (at the start of any line, indentation is allowed):
    # 
    # @example 
    #   <<< DIRECTIVE
    LINE_DIRECTIVE_REGEXP = /\A\s*<<<\s*(\S+)\s*\Z/

    included do
      if method_defined?(:preprocess)
        alias_method_chain :preprocess, :dionysus
      else
        alias_method :preprocess, :preprocess_with_dionysus
      end
    end

    # @see ClassMethods#file_preprocessors
    def file_preprocessors() self.class.file_preprocessors; end

    # @see ClassMethods#line_preprocessors
    def line_preprocessors() self.class.line_preprocessors; end

    # Alias method chain method for preprocessing a document with file_preprocessors and then
    # line_preprocessors.
    #
    # @param full_document [String] Document to preprocess
    # @return [String] the full document, with preprocessors run on it
    def preprocess_with_dionysus(full_document)
      file_preprocessors.each do |block|
        full_document = block.call(self, full_document)
      end

      return full_document if line_preprocessors.empty?

      lines = full_document.split($/)
      line_preprocessors.each do |block|
        lines.each_with_index do |ln, i|
          lines[i] = block.call(self, ln)
        end
        lines.flatten!
      end

      full_document = lines.join("\n")

      if respond_to? :preprocess_without_dionysus
        preprocess_without_dionysus(full_document)
      else
        full_document
      end
    end

    module ClassMethods
      # The list of file preprocessors
      def file_preprocessors() @file_preprocessors ||= []; end

      # The list of line preprpcessors
      def line_preprocessors() @line_preprocessors ||= []; end

      # @yield [renderer, document] Execute the provided block as a file preprocessor
      # @yieldparam renderer [Redcarpet::Render::Base] renderer for the file
      # @yieldparam document [String] document to preprocess
      # @yieldreturn [String] preprocessed document
      def preprocess_file(&block)
        file_preprocessors << block
      end

      # @yield [renderer, line] Execute the provided block as a line preprocessor
      # @yieldparam renderer [Redcarpet::Render::Base] renderer for the file
      # @yieldparam line [String] line to preprocess
      # @yieldreturn [String] preprocessed line
      def preprocess_line(&block)
        line_preprocessors << block
      end
    end
  end
end

Redcarpet::Render::HTML.send(:include, Dionysus::Redcarpet)
